package xyz.cerberu.cet.global.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import redis.clients.jedis.exceptions.JedisConnectionException;
import xyz.cerberu.cet.anime.exception.AnimeNotFoundException;
import xyz.cerberu.cet.global.domain.ExceptionEncode;
import xyz.cerberu.cet.global.domain.Result;
import xyz.cerberu.cet.global.utils.ResultUtils;
import xyz.cerberu.cet.user.exception.UploadCountException;

import javax.crypto.IllegalBlockSizeException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.time.DateTimeException;
import java.util.Enumeration;

/**
 * @author β世界
 * Created on 18:19
 * @Description 异常状态请求处理器
 */
@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class GlobalExceptionHandlerController {
    private final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

    /**
     * @author β世界 on 11:09 2021/3/16
     * 动漫不存在的异常处理
     **/
    @ResponseBody
    @ExceptionHandler(value = {AnimeNotFoundException.class})
    public Result<Object> animeNotFoundException(Exception e, HttpServletRequest request, HttpServletResponse response){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.ANIME_NOT_FOUND_EXCEPTION,"动漫不存在");
    }

    /**
     * @author β世界 on 11:04 2020/7/7
     * redis的连接错误
     **/
    @ResponseBody
    @ExceptionHandler(value = {JedisConnectionException.class})
    public Result<Object> jedisConnectionException(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genFailResult(String.valueOf(ExceptionEncode.REDIS_CONNECTION_EXCEPTION));
    }

    @ResponseBody
    @ExceptionHandler(value = {SQLException.class})
    public Result<Object> sqlException(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"参数异常");
    }

    /**
     * @author β世界 on 9:42 2020/10/16
     * 用于处理所有接口的传递参数异常的问题
     * @param e: 参数转换异常
     * @return com.Cet.common.domain.Result
     **/
    @ResponseBody
    @ExceptionHandler(value = {TypeMismatchException.class,NumberFormatException.class,IllegalStateException.class})
    public Result<Object> fullExceptionHandler(Exception e,HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"参数异常");
    }

    /**
     * @author β世界 on 10:23 2020/12/14
     * 用户认证过期
     * @param e:
     * @return com.Cet.common.domain.Result
     **/
    @ResponseBody
    @ExceptionHandler(value = {ExpiredSessionException.class})
    public Result<Object> authorExpiredException(Exception e, HttpServletRequest request){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        subject.getSession().stop();
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.USER_AUTHORITY_EXCEPTION,"用户认证过期");
    }

    /**
     * @author β世界 on 11:04 2020/7/7
     * 用户没有登录的异常处理
     **/
    @ResponseBody
    @ExceptionHandler(value = {UnauthenticatedException.class})
    public Result<Object> unauthenticatedException(Exception e, HttpServletRequest request, HttpServletResponse response){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.USER_STATUS_EXCEPTION,"用户认证状态异常，请稍后再次尝试");
    }

    /**
     * @author β世界 on 18:33 2020/9/26
     * 当用户权限不足时的报错
     * @return com.Cet.common.domain.Result
     **/
    @ResponseBody
    @ExceptionHandler(value = {AuthorizationException.class})
    public Result<Object> authorizationException(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.USER_AUTHORITY_EXCEPTION,"用户权限不足");
    }

    /**
     * @author β世界 on 15:17 2021/4/7
     * 接收到的图片id异常
     * @param e: 异常信息
     * @return xyz.cerberu.cet.global.domain.Result
     **/
    @ResponseBody
    @ExceptionHandler(value = {IllegalBlockSizeException.class})
    public Result<Object> illegalBlockSizeExceptionHandler(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"图片ID解析异常");
    }

    /**
     * @author β世界 on 8:08 2021/4/8
     * 文件获取失败
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @ResponseBody
    @ExceptionHandler(value = {MissingServletRequestPartException.class})
    public Result<Object> missingServletRequestPartExceptionHandler(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"请上传文件");
    }

    /**
     * @author β世界 on 15:19 2021/4/7
     * 用户上传间隔过短异常
     * @param e: 异常信息
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @ResponseBody
    @ExceptionHandler(value = {UploadCountException.class})
    public Result<Object> uploadCountExceptionHandler(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.USER_STATUS_EXCEPTION,e.getMessage());
    }

    /**
     * 日期参数错误
     * @author β世界 on 14:24 2021/5/31
     * @param e: 异常信息
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @ResponseBody
    @ExceptionHandler(value = {DateTimeException.class})
    public Result<Object> dateTimeExceptionHandler(Exception e, HttpServletRequest request){
        log(e,request);
        return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"日期错误");
    }

    /**
     * @author β世界 on 8:17 2021/3/12
     * 全局异常处理器
     * 主要用于日志记录
     **/
    @ResponseBody
    @ExceptionHandler(value = {Exception.class})
    public Result<Object> logExceptionHandler(Exception e, HttpServletRequest request){
        log(e,request);
        logger.warn("触发最底层的处理器");
        return ResultUtils.genErrorResult(ExceptionEncode.CODE_EXCEPTION,"服务器出错");
    }

    /**
     * @author β世界 on 8:42 2021/3/12
     * 用于日志的格式化输出和输出提示
     * @param e: 异常信息
     * @param request: 请求信息
     **/
    private void log(Exception e,HttpServletRequest request){
        logger.error("=====================触发异常===================");
        logger.error("请求来源："+request.getRequestURI());
        Enumeration<String> enumeration = request.getParameterNames();
        logger.error("请求参数:");
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            logger.error(name + " = " + request.getParameter(name));
        }

        logger.error("异常类:"+e.getClass());
        logger.error("错误信息："+e.getMessage());
        for (StackTraceElement stackTraceElement : e.getStackTrace()) {
            logger.error(stackTraceElement.toString());
        }
        logger.error("=====================异常结束===================");
    }

}
